#include <string.h>
#include "Define.h"
#include "AiotEntity.h"
#include "Core/Logger.h"
#include "MQTT/Params.h"
#include "MQTT/MQTTError.h"
#include "Core/Interface.h"
#include "Core/Utils/String.h"

extern SystemInterface globalSystemInterface;

typedef struct {
    void*       mutex;
    uint8_t     isInited;
    uint32_t    usedCount;
    int32_t     alinkId;
} AiotGlobalInfo;

AiotGlobalInfo globalAiotInfo = {nullptr,0,0, 0};

void UMQTT_InitialGlobalEnv() {

    if (globalAiotInfo.isInited == 1) {
        globalAiotInfo.usedCount++;
        return ;
    }

    globalAiotInfo.isInited = 1;

    setSystemInterface(&globalSystemInterface);
    globalAiotInfo.mutex = getSystemInterface()->createMutex();
    globalAiotInfo.usedCount++;

    initGlobalAiotSdkLog();
}

void UMQTT_DeinitialGlobalEnv() {

    destroyGlobalAiotSdkLog();

    if (globalAiotInfo.usedCount > 0) {
        globalAiotInfo.usedCount--;
    }

    if (globalAiotInfo.usedCount != 0) {
        return ;
    }

    getSystemInterface()->destroyMutex(&globalAiotInfo.mutex);

    globalAiotInfo.mutex = nullptr;
    globalAiotInfo.isInited = 0;
    globalAiotInfo.usedCount = 0;
}

int32_t UMQTT_SetServerInfo(void* handle,AiotServerAddress* address) {

    int32_t res = aiotSuccess;
    AiotEntity* entity = (AiotEntity*)handle;
    if (entity->execEnabled == 0) {
        return disableExecute;
    }

    aiotExecCountInc(entity);

    getSystemInterface()->enterMutex(entity->dataMutex);
    entity->aiotServer.port = address->port;
    res = stringDup(&entity->aiotServer.host,address->host);

    getSystemInterface()->leaveMutex(entity->dataMutex);
    aiotExecCountDec(entity);
    return res;
}

int32_t UMQTT_SetEventHandle(void* handle,AiotEventHandler eventHandle) {

    AiotEntity* entity = (AiotEntity*)handle;
    if (entity->execEnabled == 0) {
        return disableExecute;
    }

    aiotExecCountInc(entity);

    getSystemInterface()->enterMutex(entity->dataMutex);

    entity->eventHandler = eventHandle;
    getSystemInterface()->leaveMutex(entity->dataMutex);
    aiotExecCountDec(entity);
    return aiotSuccess;
}

int32_t UMQTT_SetDeviceInfo(void* handle,AiotDeviceInfo* accessInfo) {

    int32_t res = aiotSuccess;
    AiotEntity* entity = (AiotEntity*)handle;
    if (entity->execEnabled == 0) {
        return disableExecute;
    }
//    if (entity->registerMode != unknownRegMode) {
//        return registerModeHasDefine;
//    }
    aiotExecCountInc(entity);
    getSystemInterface()->enterMutex(entity->dataMutex);

    res = stringDup(&entity->aiotAccess.productKey,accessInfo->productKey);
    if (res != aiotSuccess) {
        goto func_over;
    }
    res = stringDup(&entity->aiotAccess.deviceKey,accessInfo->deviceKey);
    if (res != aiotSuccess) {
        goto func_over;
    }
    res = stringDup(&entity->aiotAccess.secretKey,accessInfo->secretKey);
    if (res != aiotSuccess) {
        goto func_over;
    }
    entity->registerMode = thirdTuple;

func_over:
    getSystemInterface()->leaveMutex(entity->dataMutex);
    aiotExecCountDec(entity);
    return res;
}

int32_t UMQTT_SetProductInfo(void* handle,AiotProductInfo* deviceInfo) {

    int32_t res = aiotSuccess;
    AiotEntity* entity = (AiotEntity*)handle;
    if (entity->execEnabled == 0) {
        return disableExecute;
    }

//    if (entity->registerMode != unknownRegMode) {
//        return registerModeHasDefine;
//    }

    aiotExecCountInc(entity);
    getSystemInterface()->enterMutex(entity->dataMutex);

    res = stringDup(&entity->aiotDeviceInfo.productKey,deviceInfo->productKey);
    if (res != aiotSuccess) {
        goto func_over;
    }

    res = stringDup(&entity->aiotDeviceInfo.deviceNo,deviceInfo->deviceNo);
    if (res != aiotSuccess) {
        goto func_over;
    }

    res = stringDup(&entity->aiotDeviceInfo.secretKey,deviceInfo->secretKey);
    if (res != aiotSuccess) {
        goto func_over;
    }
    entity->registerMode = deviceNumber;

func_over:
    getSystemInterface()->leaveMutex(entity->dataMutex);
    aiotExecCountDec(entity);
    return res;
}

int32_t UMQTT_SetChannelParams(void* handle,AiotChannelParams* channel) {

    AiotEntity* entity = (AiotEntity*)handle;
    if (entity->execEnabled == 0) {
        return disableExecute;
    }

    aiotExecCountInc(entity);

    getSystemInterface()->enterMutex(entity->dataMutex);

    entity->connectTimeout               = channel->connectTimeout;
    entity->hblInfo.interval             = channel->hbInterval;
    entity->hblInfo.maxLostTimes         = channel->hbMaxLost;
    entity->hblInfo.lostTimes            = 0;
    entity->hblInfo.lastSendAt           = getSystemInterface()->getTimestamp();
    entity->reconnectInfo.enabled        = channel->enableReConn;
    entity->reconnectInfo.interval       = channel->reConnInterval;
    entity->reconnectInfo.backOffEnabled = 0;

    entity->sendDataTimeout = channel->sendDataTimeout;
    entity->recvDataTimeout = channel->recvDataTimeout;

    getSystemInterface()->leaveMutex(entity->dataMutex);
    aiotExecCountDec(entity);
    return aiotSuccess;
}

int32_t UMQTT_SetDestroyTimeout(void* handle,int32_t destroyTimeout) {

    AiotEntity* entity = (AiotEntity*)handle;
    if (entity->execEnabled == 0) {
        return disableExecute;
    }

    aiotExecCountInc(entity);

    getSystemInterface()->enterMutex(entity->dataMutex);
    entity->destroyTimeout = destroyTimeout;
    getSystemInterface()->leaveMutex(entity->dataMutex);
    aiotExecCountDec(entity);
    return aiotSuccess;
}

int32_t UMQTT_SetChannelCred(void* handle,AiotCredInfo* credInfo) {

    int32_t res = aiotSuccess;
    AiotEntity* entity = (AiotEntity*)handle;
    if (entity->execEnabled == 0) {
        return disableExecute;
    }

    aiotExecCountInc(entity);

    getSystemInterface()->enterMutex(entity->dataMutex);

    if (entity->channelCred.credFile != nullptr) {
        getSystemInterface()->memFree(entity->channelCred.credFile);
    }

    if (credInfo->option == aiotCredNone) {
        goto func_over;
    }

    entity->channelCred.credFile = getSystemInterface()->memMalloc(credInfo->credLength + 1);
    if (entity->channelCred.credFile == nullptr) {
        res = memoryMallocFailed;
        goto func_over;
    }

    entity->channelCred.option = credInfo->option;
    entity->channelCred.credLength = credInfo->credLength;
    entity->channelCred.tlsFragment = credInfo->tlsFragment;

    memset(entity->channelCred.credFile,0x00, credInfo->credLength + 1);
    memcpy(entity->channelCred.credFile,credInfo->credFile,strlen(credInfo->credFile));

func_over:
    getSystemInterface()->leaveMutex(entity->dataMutex);
    aiotExecCountDec(entity);
    return res;
}